/*
 * user mode usb radio driver
 * 
 * right now, this driver tries to find the radio module, and reads from
 * every end point
*/

#include <stdio.h>
#include <stdint.h>
#include <libusb.h>
#include <usb.h>

#define DBG
#define VENDOR_ID 	0x0B6A
#define PRODUCT_ID  0x5346

static struct usb_device *dev;
static struct usb_dev_handle *devh;

inline char *get_string(struct usb_dev_handle *devh, uint8_t index)
{
	static char buf[256];
	/* TODO
	 * use usb_control_msg to get full length, like so
	 * libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
	 * 		LIBUSB_REQUEST_GET_DESCRIPTOsR, (LIBUSB_DT_STRING << 8) | desc_index,
	 * 		langid, data, length, 1000);
	 * not really that important though
	 */
	if(index)
		if(usb_get_string_simple(devh, index, buf, 255) > 0)
			return buf;
}
struct usb_device *get_device()
{
	struct usb_bus *bus;
	
#ifdef DBG
	printf("looking for %04X:%04X\n", VENDOR_ID, PRODUCT_ID);
#endif
	for(bus = usb_busses; bus; bus = bus->next){
		struct usb_device *dev;

		for(dev = bus->devices; dev; dev = dev->next){
#ifdef DBG
			printf("bus: %s dev: %s id: %04X:%04X\n", bus->dirname, 
				dev->filename,
				dev->descriptor.idVendor, 
				dev->descriptor.idProduct);
#endif
			if(dev->descriptor.idVendor == VENDOR_ID
					&& dev->descriptor.idProduct == PRODUCT_ID){
				return dev;
			}
		}
	}
	return NULL;
}
void print_bytes(char *bytes, unsigned long len)
{
	len = (unsigned long)bytes + len;
	while((unsigned long)bytes < len){
		printf("%02X ", *bytes);
		bytes++;
	}
}
void radio_init()
{
	usb_init();
	usb_find_busses();
	usb_find_devices();

	if(!(dev = get_device())){
		printf("device not found\n");
		exit(-1);
	}
	printf("device found\n");

	if(!(devh = usb_open(dev))){
		printf("could not open device, try running as root\n");
		exit(-1);
	}

	printf("\tmanufacturer: %s\n",
		get_string(devh, dev->descriptor.iManufacturer));
	printf("\tproduct: %s\n",
		get_string(devh, dev->descriptor.iProduct));
	printf("\tserial: %s\n",
		get_string(devh, dev->descriptor.iSerialNumber));
}
void radio_shutdown()
{
	usb_close(devh);
}
int main(int argc, char *argv[])
{
	char buf[256];
	int read_count;

	int c, i, a, e;
	struct usb_config_descriptor *config_desc;
	struct usb_interface *interface;
	struct usb_interface_descriptor *interface_desc;
	struct usb_endpoint_descriptor *ep_desc;

	radio_init();

	for(c = 0; c < dev->descriptor.bNumConfigurations; c++){
		config_desc = &dev->config[c];
		if(usb_set_configuration(devh, c) != 0){
			printf("could not set config\n");
			break;
		}
		for(i = 0; i < config_desc->bNumInterfaces; i++){
			interface = &config_desc->interface[i];
			if(usb_claim_interface(devh, i) != 0){
				printf("could not claim if\n");
				break;
			}
			for(a = 0; a < interface->num_altsetting; a++){	
				interface_desc = &interface->altsetting[a];
				if(usb_set_altinterface(devh, a) != 0){
					printf("could not set altif\n");
					break;
				}

				for(e = 0; e < interface_desc->bNumEndpoints; e++){
					// try a bulk read
					if((read_count = usb_bulk_read(devh, e, buf, 256, 10)) <= 0)
						printf("fuck bulk\n");
					else
						print_bytes(buf, read_count);

					// interrupt read
					read_count = usb_interrupt_read(devh, e, buf, 256, 10)
					if(read_count <= 0)
						printf("fuck interrupt\n");
					else
						print_bytes(buf, read_count);
				}
			}
			usb_release_interface(devh, i); 
		}
	}

	radio_shutdown();
	return 0;
}
